package server.console.groups.update;

import com.alee.extended.painter.TitledBorderPainter;
import com.alee.extended.panel.GroupPanel;
import com.alee.extended.panel.GroupingType;
import com.alee.extended.window.WebProgressDialog;
import com.alee.laf.button.WebButton;
import com.alee.laf.label.WebLabel;
import com.alee.laf.list.WebList;
import com.alee.laf.list.WebListModel;
import com.alee.laf.optionpane.WebOptionPane;
import com.alee.laf.panel.WebPanel;
import com.alee.laf.rootpane.WebDialog;
import com.alee.laf.rootpane.WebFrame;
import com.alee.laf.scroll.WebScrollPane;
import com.alee.laf.text.WebTextPane;
import com.alee.managers.notification.NotificationManager;
import com.alee.managers.notification.WebNotification;
import com.alee.utils.FileUtils;
import com.fasterxml.jackson.core.type.TypeReference;
import constants.ServerConstants;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import server.console.Start;
import tools.DateUtil;
import tools.JsonUtil;

import javax.swing.*;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import java.awt.*;
import java.awt.datatransfer.StringSelection;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.*;
import java.net.ConnectException;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @author CHMS
 *         创建日期 2016/9/18
 */
public class UpdateServer extends WebDialog {

    private static final String URL_UPDATE_LOG = "http://114.215.69.243/updatelog.json";
    private static final String URL_SERVER_JAR = "http://114.215.69.243/patchs/";
    private static final Logger log = LogManager.getLogger();
    private static final WebLabel lasttimes = new WebLabel();
    private static final WebList patchList = new WebList(new WebListModel<>());
    private static final List<String> patchListData = new ArrayList<>();
    private static UpdateServer instance;
    private static Map<String, Map<String, String>> versions;
    private static boolean findnewver;
    private final WebTextPane patchLog = new WebTextPane();
    private final WebButton updateNow = new WebButton();
    private final WebLabel newverlabel2 = new WebLabel();
    private String toversion;
    private WebButton updateTo;

    {
        toversion = getNewVersion();
        setLasttimes("");
    }

    public UpdateServer(WebFrame owner) {
        super(owner, "检查服务端更新", true);

        setPreferredSize(new Dimension(800, 600));
        add(new WebPanel(new BorderLayout(5, 5)) {
            {
                setMargin(5);
                add(new WebPanel(new GroupPanel(5, false) {
                    {
                        add(new WebLabel("当前服务端版本：" + Start.getInstance().getServer_version()));

                        final WebLabel newverlabel = new WebLabel("服务端最新版本：");
                        findnewver = !getNewVersion().equals(Start.getInstance().getServer_version());
                        updateNewVerLabel();
                        updateNow.addActionListener(new ActionListener() {
                            @Override
                            public void actionPerformed(ActionEvent e) {
                                if (findnewver) {
                                    toversion = getNewVersion();
                                    downUpdate();
                                } else {
                                    new CheckUpdateRun().run();
                                }
                            }
                        });

                        add(new GroupPanel(5, new GroupPanel(newverlabel, newverlabel2), updateNow));
                        add(lasttimes);
                    }
                }).setMargin(5, 10, 0, 0), BorderLayout.NORTH);

                updateTo = new WebButton("更新到此版本");
                updateTo.setMargin(5);
                updateTo.addActionListener(new ActionListener() {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        String select_version = (String) patchList.getSelectedValue();
//                        if (Start.getInstance().getServer_version().equals(select_version)) {
//                            WebOptionPane.showMessageDialog(UpdateServer.this, "当前已经是该版本了");
//                            return;
//                        }
                        if (WebOptionPane.showConfirmDialog(instance, "当前选择的版本是：" + select_version + " 是否继续？", "", WebOptionPane.YES_NO_OPTION) == WebOptionPane.NO_OPTION) {
                            return;
                        }
                        toversion = (String) patchList.getSelectedValue();
                        downUpdate();
                    }
                });
                add(new GroupPanel(GroupingType.fillFirst, false,
                        new WebPanel() {
                            {
                                setPreferredWidth(200);
                                patchListData.clear();
                                patchListData.addAll(versions.keySet());
                                setPainter(new TitledBorderPainter("历史更新"));
                                patchList.getWebModel().setElements(patchListData);
                                patchList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
                                patchList.addListSelectionListener(new ListSelectionListener() {
                                    @Override
                                    public void valueChanged(ListSelectionEvent e) {
                                        if (patchList.getSelectedValue() != null) {
                                            Map<String, String> map = versions.get(patchList.getSelectedValue().toString());
                                            String normallog = map.get("Log");
                                            String twLog = map.get("TWLog");
                                            patchLog.setText(normallog + (ServerConstants.ServerFlags.台湾服.check() && twLog != null ? "\r\n\r\n" + twLog : ""));
                                        }
                                    }
                                });
                                add(new WebScrollPane(patchList));
                            }
                        }, updateTo
                ), BorderLayout.WEST);

                add(new WebPanel() {
                    {
                        setPainter(new TitledBorderPainter("更新内容"));
                        patchLog.setEditable(false);
                        add(new WebScrollPane(patchLog));
                        add(new WebPanel() {
                            {
                                add(new WebButton("复制到剪贴板") {
                                    {
                                        setMargin(5);
                                        addActionListener(e -> {
                                            Toolkit.getDefaultToolkit().getSystemClipboard().setContents(new StringSelection(patchLog.getText()), null);
                                            WebOptionPane.showMessageDialog(UpdateServer.this, "复制成功！");
                                        });
                                    }
                                }, BorderLayout.EAST);
                            }
                        }, BorderLayout.SOUTH);
                    }
                }, BorderLayout.CENTER);
            }
        });
        patchList.setSelectedIndex(0);
    }

    public static UpdateServer getInstance(WebFrame owner) {
        if (instance == null) {
            instance = new UpdateServer(owner);
        }
        return instance;
    }

    public static String getNewVersion() {
        List<String> verlist = new ArrayList<>(versions.keySet());
        verlist.sort((o1, o2) -> {
            String[] split1 = o1.split("\\.");
            String[] split2 = o2.split("\\.");
            for (int i = 0; i < 3; i++) {
                int n1 = Integer.parseInt(split1[i]);
                int n2 = Integer.parseInt(split2[i]);
                if (n1 > n2) {
                    return -1;
                } else if (n1 < n2) {
                    return 1;
                }
            }
            return 0;
        });
        return verlist.size() > 0 ? verlist.get(0) : "1.0.0";
    }

    public void setLasttimes(String lasttime) {
        lasttimes.setText("最后检查更新时间：" + lasttime);
    }

    public void updateNewVerLabel() {
        if (findnewver) {
            newverlabel2.setText(getNewVersion() + " new!");
            newverlabel2.setForeground(Color.RED);
            updateNow.setText("立即更新");
        } else {
            newverlabel2.setText("已经是最新");
            updateNow.setText("检查更新");
        }
    }

    public void downUpdate() {
        new SwingWorker() {
            @Override
            protected Object doInBackground() {
                updateNow.setEnabled(false);
                updateTo.setEnabled(false);
                FileUtils.clearDirectory(new File("update_temp"));
                WebProgressDialog progressDialog = new WebProgressDialog("下载更新");
                progressDialog.setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
                progressDialog.setPreferredProgressWidth(300);
                progressDialog.setVisible(true);
                progressDialog.setAlwaysOnTop(true);
                progressDialog.setText("正在下载更新包 v." + toversion + "……");
                try {
                    URL url = new URL(URL_SERVER_JAR + toversion + "/Server.jar");
                    URLConnection connection = url.openConnection();
                    try (InputStream inputStream = connection.getInputStream()) {
                        File file = new File("update_temp/Server.jar");
                        File dir = new File("update_temp");
                        if (!dir.exists()) {
                            dir.mkdirs();
                        }
                        try (FileOutputStream fileOutputStream = new FileOutputStream(file)) {
                            byte[] buff = new byte[1024];
                            int len;
                            int total = 0;
                            while ((len = inputStream.read(buff)) != -1) {
                                fileOutputStream.write(buff, 0, len);
                                total += len;
                                progressDialog.setProgress((int) (((double) total / connection.getContentLength()) * 100));
                            }
                        }
                    }
                } catch (IOException e) {
                    WebOptionPane.showMessageDialog(UpdateServer.this, "连接更新服务器失败，请稍后重试");
                    return null;
                } finally {
                    progressDialog.dispose();
                    updateNow.setEnabled(true);
                    updateTo.setEnabled(true);
                }
                if (Boolean.valueOf(versions.get(toversion).get("reload"))) {
                    Start.makeReloadFile();
                }
                WebOptionPane.showMessageDialog(UpdateServer.this, "更新完成，请手动重启服务端。\r\n若选择的版本错误，可重新选择版本并更新即可。");
                return null;
            }
        }.execute();
    }

    public static class CheckUpdateRun implements Runnable {

        private static WebNotification notification;
        private static boolean running = false;

        @Override
        public void run() {
            try {
                if (running) {
                    return;
                } else {
                    running = true;
                }
                URL url = new URL(URL_UPDATE_LOG);
                try (InputStreamReader inputStreamReader = new InputStreamReader(url.openStream())) {
                    try (BufferedReader bufferedReader = new BufferedReader(inputStreamReader)) {
                        StringBuilder stringBuilder = new StringBuilder();
                        String buff;
                        while ((buff = bufferedReader.readLine()) != null) {
                            stringBuilder.append(buff);
                        }
                        versions = JsonUtil.getMapperInstance().readValue(stringBuilder.toString(), new TypeReference<Map<String, Map<String, String>>>() {
                        });
                        if (Start.getInstance().getServer_version().compareTo(getNewVersion()) < 0) {
                            findnewver = true;
                            patchListData.clear();
                            patchListData.addAll(versions.keySet());
                            patchList.getWebModel().setElements(patchListData);
                            UpdateServer.getInstance(Start.getInstance()).updateNewVerLabel();
                            if (notification == null) {
                                notification = new WebNotification();
                                notification.setIcon(Start.loadIcon("newversion.png"));
                                notification.setClickToClose(false);
                                final WebLabel message = new WebLabel("服务端检测到新的版本 " + getNewVersion());
                                final WebButton lookbutton = new WebButton("立即查看"), cancelbutton = new WebButton("稍后");
                                lookbutton.addActionListener(e -> {
                                    notification.hidePopup();
                                    Start.getInstance().showUpdateServer();
                                });
                                cancelbutton.addActionListener(e -> notification.hidePopup());
                                notification.setContent(new GroupPanel(5, false, message, new WebPanel() {
                                    {
                                        setOpaque(false);
                                        add(new GroupPanel(2, lookbutton, cancelbutton), BorderLayout.EAST);
                                    }
                                }));
                                NotificationManager.showNotification(notification);
                            }
                        }
                        UpdateServer.getInstance(Start.getInstance()).setLasttimes(DateUtil.getNowTime());
                    }
                }
            } catch (ConnectException e) {
                if (e.getMessage().contains("Connection timed out: connect")) {
                    log.error("连接更新服务器超时");
                }
            } catch (IOException e) {
                log.error("连接更新服务器失败", e);
            } finally {
                running = false;
            }
        }
    }
}
